package com.cdz.common.utils;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * AES加密解密工具类（目前AES比DES和DES3更安全，速度更快，对称加密一般采用AES）
 */
public class AesUtils {
    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";

    public static String encrypt(String data,String secretKey,String iv) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static String decrypt(String encryptedData,String secretKey,String iv) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] original = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(original, StandardCharsets.UTF_8);
    }


    /**
     * 获取 token
     * @return
     * @throws Exception
     */
    public static String getToken() throws Exception {
        String OperatorID = "573348119";   // 运营商标识

        String OperatorSecret = "OsmifJFIbn9w7etf"; // 运营商秘钥
        String SigSecret = "8ftLPzo5ZSiCZzpK"; // 签名秘钥
        String dataSecret  = "tI76pVFXlZNgiIIc"; // 数据加密秘钥
        String dataSecretIV = "JqCZF7U2kSg2TWY2"; // 16 bytes IV

        String data = JSONObject.of("OperatorID", OperatorID, "OperatorSecret", OperatorSecret).toString();
        System.out.println("data:"+data);
        String encryptData = AesUtils.encrypt(data,dataSecret,dataSecretIV);
//        String decryptStr = AesUtils.decrypt(encryptData,dataSecret,dataSecretIV);
//        System.out.println("解密数据："+ decryptStr);
        JSONObject dtoJson = new JSONObject();
        dtoJson.put("OperatorID",OperatorID);
        dtoJson.put("Data",encryptData);
        dtoJson.put("TimeStamp",DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS));
        dtoJson.put("Seq","0001");
        String sign = sign(SigSecret, OperatorID,encryptData,dtoJson.getString("TimeStamp"),dtoJson.getString("Seq"));
        dtoJson.put("Sig",sign);
        String reqParams = JSONObject.toJSONString(dtoJson);
        System.out.println("请求参数: "+ reqParams);
        String post = HttpUtil.post("http://uat-devapi.fcwenergy.com/evcs/573348119/query_token", reqParams);
        JSONObject jsonObject = JSONObject.parseObject(post);
        if ("0".equals(jsonObject.getString("Ret"))) {
            
        }
        System.out.println("响应参数: "+ post);
        return "";
    }


    public static void main(String[] args) throws Exception {

        getToken();

//        OsmifJFIbn9w7etf
//        8ftLPzo5ZSiCZzpK
//        tI76pVFXlZNgiIIc
//        JqCZF7U2kSg2TWY2

//        for (int i = 0; i < 4; i++) {
//            System.out.println(StringUtils.generateRandomString(16));
//        }
    }




    /**
     * HmacMd5的计算公式为：HMAC(K,M) = H(K⊕opad∣H(K⊕ipad∣M))
     * 其中:K是密钥(byte[] key)，长度可为64字节(后面涉及描述都是以字节byte进行)，若小于该长度，在密钥后面用0(即0x00)补齐。
     * M是消息内容(byte[] m)；
     * H是散列函数(此处采用MD5)；
     * opad和ipad分别是由若干个0x5c和0x36组成的字符串；
     * ⊕表示异或运算；
     * ∣表示连接操作。
     **/
    private static byte[] getHMacMD5Bytes(byte[] key, byte[] m) {
        try {
            //定义长度
            int length = 64;
            //定义opad和ipad
            byte[] opad = new byte[length];
            byte[] ipad = new byte[length];
            for (int i = 0; i < 64; i++) {
                opad[i] = 0x5C;
                ipad[i] = 0x36;
            }
            byte[] actualKey = key;
            byte[] keyArr = new byte[length];
            //如果密钥长度，大于64字节，就使用MD5算法计算其散列值，作为密钥
            if (key.length > length) {
                actualKey = md5(key);
            }
            for (int i = 0; i < actualKey.length; i++) {
                keyArr[i] = actualKey[i];
            }
            //如果密钥长度不足64字节，就使用0x00补齐到64字节
            if (actualKey.length < length) {
                for (int i = key.length; i < length; i++)
                    keyArr[i] = 0x00;
            }
            //使用密钥和ipad进行异或运算【K⊕ipad】
            byte[] kIpadXorResult = new byte[length];
            for (int i = 0; i < length; i++) {
                kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]);
            }
            //将待加密数据M追加到kIpadXorResult后面【K⊕ipad∣M】
            byte[] firstAppendResult = new byte[kIpadXorResult.length + m.length];
            for (int i = 0; i < kIpadXorResult.length; i++) {
                firstAppendResult[i] = kIpadXorResult[i];
            }
            for (int i = 0; i < m.length; i++) {
                firstAppendResult[i + keyArr.length] = m[i];
            }
            //做MD5运算【H(K⊕ipad∣M)】
            byte[] firstHashResult = md5(firstAppendResult);

            //使用密钥和opad进行异或运算【K⊕opad】
            byte[] kOpadXorResult = new byte[length];
            for (int i = 0; i < length; i++) {
                kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]);
            }
            //将firstHashResult追加到kOpadXorResult后面【K⊕opad∣H(K⊕ipad∣M)】
            byte[] secondAppendResult = new byte[kOpadXorResult.length + firstHashResult.length];
            for (int i = 0; i < kOpadXorResult.length; i++) {
                secondAppendResult[i] = kOpadXorResult[i];
            }
            for (int i = 0; i < firstHashResult.length; i++) {
                secondAppendResult[kOpadXorResult.length + i] = firstHashResult[i];
            }
            //做MD5运算【H(K⊕opad∣H(K⊕ipad∣M))】
            return md5(secondAppendResult);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * MD5(产生出一个128位（16字节）的散列值)
     **/
    private static byte[] md5(byte[] str) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(str);
        return md.digest();
    }

    /**
     * HEX转化为字符串
     **/
    private static String bytesToHexString(byte[] m) {
        StringBuilder stringBuilder = new StringBuilder();
        if (m == null || m.length <= 0) {
            return null;
        }
        for (int i = 0; i < m.length; i++) {
            int v = m[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString().toUpperCase();
    }

    public static String sign(String signKey, String operatorId, String data, String timeStamp, String seq){
        String m = new StringBuilder(operatorId).append(data).append(timeStamp).append(seq).toString();
        byte[] macMD5 = AesUtils.getHMacMD5Bytes(signKey.getBytes(), m.getBytes());
        return AesUtils.bytesToHexString(macMD5);
    }

}

